package com.googlecode.yoohoo.io.socket.stream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

import com.googlecode.yoohoo.utils.Constants;
import com.googlecode.yoohoo.utils.FilterCreator;
import com.googlecode.yoohoo.utils.OsgiUtils;
import com.googlecode.yoohoo.xmppcore.connection.IConnectionContext;
import com.googlecode.yoohoo.xmppcore.protocol.parsing.IXmppParsingFactory;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.Stanza;
import com.googlecode.yoohoo.xmppcore.stanza.IStanzasHandler;
import com.googlecode.yoohoo.xmppcore.stanza.StanzasHandler;
import com.googlecode.yoohoo.xmppcore.stream.INegotiationContext;

public abstract class AbstractStreamFeaturesContributedNegotiant extends AbstractStreamNegotiant {
	private static final Log log = LogFactory.getLog(AbstractStreamFeaturesContributedNegotiant.class);
	@SuppressWarnings("unchecked")
	@Override
	protected void doNegotiate(INegotiationContext context, String message) {
		BundleContext bundleContext = ((NegotiationContext)context).getBundleContext();
		IXmppParsingFactory parsingFactory = (IXmppParsingFactory)OsgiUtils.getServiceInstance(bundleContext,
				IXmppParsingFactory.class, Constants.CONSTANT_XMPP_STREAM);

		Object object = null;
		try {
			object = parsingFactory.parse(message);
		} catch (Exception e) {
			// ignore
			if (log.isTraceEnabled()) {
				log.trace(e.getMessage(), e);
			}
		}
		
		if (object == null || !(object instanceof Stanza)) {
			// stream feature contribution can handle stanza only. If the message isn't a stanza,
			// passing the message to next negotiant.
			passToNextNegotiant(context, message);
			return;
		}
		
		Stanza stanza = (Stanza)object;
		try {
			IStanzasHandler<IConnectionContext> stanzasHandler = null;
			ServiceReference[] references = bundleContext.getServiceReferences(StanzasHandler.class.getName(),
				FilterCreator.equal(IStanzasHandler.KEY_STANZAS_HANDLER_TYPE, getPhase().toString()));
			if (references != null && references.length > 0) {
				stanzasHandler = (IStanzasHandler<IConnectionContext>)bundleContext.getService(references[0]);
			}
			
			if (stanzasHandler != null && stanzasHandler.process(context, stanza)) {
				return;
			}
		} catch (InvalidSyntaxException e) {
			// ???
			throw new RuntimeException("Can't get stanza handler for stream feature contributions.");
		}
		
		// no stream feature contribution can process the request, call next negotiant
		passToNextNegotiant(context, message);
	}

	private void passToNextNegotiant(INegotiationContext context, String message) {
		nextPhase(context);
		if (nextNegotiant != null) {
			nextNegotiant.negotiate(context, message);
		}
	}
}
